package server

import (
	"context"
	"errors"
	"fmt"
	"time"

	"github.com/coreos/etcd/clientv3"
)

/**
服务注册步骤：
1、connect etcd
2、create lease -> keepLive -> listen keepLive
3、put value
*/

// ETCD_TIMEOUT 定义一个超时时间
const ETCD_TIMEOUT = 3 * time.Second

// EtcdStruct 定义一个etcd结构体
type EtcdRegister struct {
	cli                    *clientv3.Client
	endpoints              []string
	LeaseGrantResponse     *clientv3.LeaseGrantResponse
	LeaseKeepAliveResponse <-chan *clientv3.LeaseKeepAliveResponse
}

// NewEtcdStruct 实例化一个etcd结构体
func NewEtcdStruct(endpoints []string) (*EtcdRegister, error) {
	config := clientv3.Config{
		Endpoints:   endpoints,
		DialTimeout: ETCD_TIMEOUT,
	}
	cli, err := initEtcd(config)
	if err != nil {
		return nil, err
	}
	Ts := &EtcdRegister{
		cli:       cli,
		endpoints: config.Endpoints,
	}
	return Ts, nil
}

// initEtcd 创建一个etcd连接
func initEtcd(config clientv3.Config) (*clientv3.Client, error) {
	return clientv3.New(config)
}

// CreateLease 创建租约
func (e *EtcdRegister) createLeaseAndSetKeepLive(ttl int64) error {
	lease, err := e.cli.Grant(context.TODO(), ttl)
	if err != nil {
		return err
	}
	e.LeaseGrantResponse = lease
	//续租
	LeaseKeepAliveResponse, err := e.cli.KeepAlive(context.TODO(), lease.ID)
	if err != nil {
		return err
	}
	e.LeaseKeepAliveResponse = LeaseKeepAliveResponse
	go e.ListenLease()
	return nil
}

// PutWithLease put值
func (e *EtcdRegister) putWithLease(key, value string) error {
	ctx, cancel := context.WithTimeout(context.Background(), ETCD_TIMEOUT)
	_, err := e.cli.Put(ctx, key, value, clientv3.WithLease(e.LeaseGrantResponse.ID))
	cancel()
	return err
}

// ListenLease 监听续租（其实就是循环从<-chan *LeaseKeepAliveResponse 这个chan取值 能取到就表示续租成功 每次续租的时间间隔大概是租约时间的三分之一）
func (e *EtcdRegister) ListenLease() {
	for {
		select {
		case res := <-e.LeaseKeepAliveResponse:
			if res == nil {
				fmt.Println("time:", time.Now().Unix(), "  ", e.LeaseGrantResponse.ID, ":lease close")
				return
			} else {
				fmt.Println("time:", time.Now().Unix(), "  ", e.LeaseGrantResponse.ID, ":lease success")
			}
		}
	}
}

// RegisterServer 注册服务
func (e *EtcdRegister) RegisterServer(key, value string, ttl int64) (err error) {
	err = e.createLeaseAndSetKeepLive(ttl)
	if err != nil {
		//fmt.Println("create lease failure err:", err)
		return errors.New(fmt.Sprintf("create lease failure err:%s", err))
	}
	err = e.putWithLease(key, value)
	if err != nil {
		//fmt.Println("put data to etcd failure,err:", err)
		return errors.New(fmt.Sprintf("put data to etcd failure,err:%s", err))
	}
	return nil
}
